package org.common.utils.rpc.generator;
import org.common.utils.handler.HandlerTool;
import org.common.utils.rpc.core.RpcInterface;
import org.common.utils.rpc.core.RpcSenders;
import org.common.utils.rpc.entity.Metadata;
import org.common.utils.rpc.generator.entity.ClassBuilder;
import org.common.utils.rpc.generator.entity.GeneratorInfo;
import org.common.utils.rpc.generator.handler.methodbody.AbstractHandler;
import org.common.utils.rpc.generator.handler.methodbody.ReturnType;
import org.common.utils.tool.ClassTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态生成Rpc接口，客户端请求实现对象
 * @author zhouzhibing
 * @date 2025/11/15 18:27
 */
public class GeneratorImplement {

    private static final Logger log = LoggerFactory.getLogger(GeneratorImplement.class);
    /**
     * 方法体处理器 <方法体返回类型字符串， 处理器>
     */
    private static final Map<String , AbstractHandler> HANDLER_MAP = HandlerTool.initChildHandler("org.common.utils.rpc.generator.handler", AbstractHandler.class, AbstractHandler::getTypeName);
    /**
     * 实现类列表
     */
    private final Map<Class<?> , Object> implementMap = new ConcurrentHashMap<>();
    /**
     * 是否保存生成的类文件
     */
    private boolean openSaveFile;

    /**
     * 生成实现类
     */
    public void generator(RpcSenders senders , String packageName) {
        Set<Class<?>> allClass = ClassTool.getAllClass(packageName);
        for (Class<?> clazz : allClass) {
            // 判断是否是Rpc接口
            RpcInterface rpcInterface = clazz.getAnnotation(RpcInterface.class);
            if(rpcInterface == null) {
                continue;
            }

            // 判断是否是接口，不是接口类型。
            if (!clazz.isInterface()) {
                continue;
            }

            generator(senders , clazz);
        }
    }

    /**
     * 生成实现类
     * @param interfaceClass 接口类
     */
    private void generator(RpcSenders senders , Class<?> interfaceClass) {
        String interfaceClassName = interfaceClass.getSimpleName();
        String implementClassName = interfaceClassName + "Impl";
        String fullClassName = interfaceClass.getPackageName() + "." + implementClassName;
        ClassBuilder classBuilder = new ClassBuilder(fullClassName);

        Method currentMethod = null;
        String currentMethodBody = null;
        try {
            Method[] methods = interfaceClass.getDeclaredMethods();

            classBuilder.addInterface(interfaceClass.getName());
            classBuilder.addField("private final " + RpcSenders.class.getName() + " rpcSenders;");
            classBuilder.addField("private final " + Map.class.getName() + " metadataMap;");
            classBuilder.addConstructor(
            "public " + implementClassName + "(" + RpcSenders.class.getName() + " rpcSenders) {\n" +
                                "this.rpcSenders = rpcSenders;\n" +
                                "this.metadataMap = new java.util.HashMap(" + methods.length + ");\n" +
                                 putMetadataMap(interfaceClass , methods) +
                            "}\n"
            );

            for (Method method : methods) {
                currentMethod = method;
                currentMethodBody = getMethodBody(interfaceClass , method);
                classBuilder.addMethod(currentMethodBody);
            }

            Class<?> clazz = classBuilder.build();
            Constructor<?> constructor = clazz.getConstructor(RpcSenders.class);
            implementMap.put(interfaceClass, constructor.newInstance(senders));
            log.info("generator success , class : {} , interface : {}" , fullClassName , interfaceClassName);
        } catch (Exception e) {
            if(currentMethod != null)
                throw new RuntimeException(currentMethod + "\n" + currentMethodBody, e);
            else
                throw new RuntimeException(e);
        } finally {
            if(openSaveFile) {
                //查看生成的类，主要用于调试。
                classBuilder.writeFile();
            }
        }
    }

    /**
     * 创建metadataMap
     * @param interfaceClass 接口类
     * @param methods 方法列表
     * @return metadataMap创建字符串
     */
    private String putMetadataMap(Class<?> interfaceClass , Method[] methods) {
        String metadataClassName = Metadata.class.getName();
        StringBuilder putMetadataMap = new StringBuilder();
        for (Method method : methods) {
            String methodName = method.getName();
            putMetadataMap.append("this.metadataMap.put(\"").append(methodName).append("\", new ").append(metadataClassName)
                    .append("(").append(interfaceClass.getName()).append(".class, \"").append(methodName).append("\"));\n");
        }
        return putMetadataMap.toString();
    }

    /**
     * 获取方法体
     * @param interfaceClass 接口类
     * @param method  方法
     * @return 方法体字符串
     */
    private String getMethodBody(Class<?> interfaceClass , Method method) {
        String returnTypeName = method.getReturnType().getName();
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        int argCount = parameterTypes.length;

        StringBuilder body = new StringBuilder();
        body.append("public ").append(returnTypeName).append(" ").append(methodName).append("(");
        for (int i = 0; i < argCount; i++) {
            body.append(parameterTypes[i].getName()).append(" ").append("arg").append(i);
            if(i < argCount - 1) {
                body.append(", ");
            }
        }
        body.append(") {\n");

        // 方法体内容
        AbstractHandler handler = getHandler(returnTypeName);
        GeneratorInfo generatorInfo = new GeneratorInfo(interfaceClass , method);
        String content = handler.handler(generatorInfo);

        body.append(content).append("\n");
        body.append("}\n");

        return body.toString();
    }


    /**
     * 获取方法体处理器
     * @param returnTypeName 方法返回类型
     * @return 方法体处理器
     */
    private AbstractHandler getHandler(String returnTypeName) {
        AbstractHandler handler = HANDLER_MAP.get(returnTypeName);
        if(handler == null)
            handler = HANDLER_MAP.get(ReturnType.OBJECT.getName());
        return handler;
    }

    /**
     * 获取实现对象
     * @param clazz  类
     * @return 实现对象
     * @param <T> 实现对象类型
     */
    public <T> T getImplement(Class<T> clazz) {
        return (T)implementMap.get(clazz);
    }

    /**
     * 生成类文件，是否保存成文件的开关
     * @param open 打开或者关闭
     */
    public void saveGeneratorFile(boolean open) {
        openSaveFile = open;
    }
}
